﻿Imports System.ComponentModel
Imports DAL
Imports System.Linq
Imports System.Drawing.Drawing2D
Imports System.Globalization

Public Class UcGrilleHoraire

#Region "Variables"
    'VARIABLES D'EN-TÊTES (COLONNES ET RANGÉES)
    Public Enum TypeDeTriEnum
        Temps
        Jours
        Employes
    End Enum
    Private _TypeColonnes As TypeDeTriEnum = TypeDeTriEnum.Jours
    Private _TypeRangees As TypeDeTriEnum = TypeDeTriEnum.Employes
    <Category("My properties"), Description("Le type de donnée des colonnes")> _
    Public Property TypeColonnes() As TypeDeTriEnum
        Get
            Return Me._TypeColonnes
        End Get
        Set(ByVal Value As TypeDeTriEnum)
            If Value = TypeDeTriEnum.Jours Then
                NbColonne = 7
            End If
            Me._TypeColonnes = Value
        End Set
    End Property
    <Category("My properties"), Description("Le type de donnée des rangées")> _
    Public Property TypeRangees() As TypeDeTriEnum
        Get
            Return Me._TypeRangees
        End Get
        Set(ByVal Value As TypeDeTriEnum)
            Me._TypeRangees = Value
        End Set
    End Property
    Private _HSplitterDistance As Integer = 50
    Private _VSplitterDistance As Integer = 50
    Private _SplitterWidth As Integer = 5
    Private LargeurColonne As Integer
    Private HauteurRangee As Integer
    Private _LargeurColonneMin As Integer = 120
    Private _HauteurRangeeMin As Integer = 45
    Private ColScroll As Integer = 0
    Private RowScroll As Integer = 0
    Private _Blocked As Boolean = False
    Public DragIn As Boolean = False

    <Category("My properties"), Description("La position du splitter horizontal")> _
    Public Property HSplitterDistance() As Integer
        Get
            Return Me._HSplitterDistance
        End Get
        Set(ByVal Value As Integer)
            Me._HSplitterDistance = Math.Max(Value, 45)
        End Set
    End Property
    <Category("My properties"), Description("Définit si la grille est modifiable")> _
    Public Property Blocked() As Boolean
        Get
            Return Me._Blocked
        End Get
        Set(ByVal Value As Boolean)
            Me._Blocked = Value
            DessinerGrille(True)
            ReDessiner()
        End Set
    End Property
    <Category("My properties"), Description("La position du splitter vertical")> _
    Public Property VSplitterDistance() As Integer
        Get
            Return Me._VSplitterDistance
        End Get
        Set(ByVal Value As Integer)
            Me._VSplitterDistance = Math.Max(Value, 90)
        End Set
    End Property
    <Category("My properties"), Description("L'epaisseur du splitter")> _
    Public Property SplitterWidth() As Integer
        Get
            Return Me._SplitterWidth
        End Get
        Set(ByVal Value As Integer)
            Me._SplitterWidth = Value
        End Set
    End Property
    <Category("My properties"), Description("Largeur minimum des colonnes")> _
    Public Property LargeurColonneMin() As Integer
        Get
            Return Me._LargeurColonneMin
        End Get
        Set(ByVal Value As Integer)
            Me._LargeurColonneMin = Math.Max(Value, 30)
        End Set
    End Property
    <Category("My properties"), Description("Hauteur minimum des rangees")> _
    Public Property HauteurRangeeMin() As Integer
        Get
            Return Me._HauteurRangeeMin
        End Get
        Set(ByVal Value As Integer)
            Me._HauteurRangeeMin = Math.Max(Value, 25)
        End Set
    End Property
    <Category("My properties"), Description("Place automatiquement les employés ayant des plages horaires en premier")> _
    Private _TriEmployeParActivite As Boolean = False
    Public Property TriEmployeParActivite() As Integer
        Get
            Return Me._TriEmployeParActivite
        End Get
        Set(ByVal Value As Integer)
            Me._TriEmployeParActivite = Value
        End Set
    End Property
    Private AuDessusColonne As Integer = -1
    'EVENEMENTS
    Event ColonneClickEvent As EventHandler
    Event PlageSelected As EventHandler
    Event modification As EventHandler
    Event ViewDetail As EventHandler
    Private NbColonne As Integer
    Private NbRangee As Integer
    'VARIABLES IMAGES
    Private bmpColonne As Bitmap = New Bitmap(1, 1)
    Private bmpRangee As Bitmap = New Bitmap(1, 1)
    Private bmpGrille As Bitmap = New Bitmap(1, 1)
    Private bmpBordure As Bitmap = New Bitmap(1, 1)
    Private bmpPricipal As Bitmap = New Bitmap(1, 1)
    'VARIABLES CONTROLES
    'VARIABLES DE POSITION DU CURSEUR
    Public MouseOverGrid As Boolean = False
    Private MouseOverHSplitter As Boolean = False
    Private MouseOverVSplitter As Boolean = False
    Private MouseCell As Point = New Point()
    Private StartCell As Point = New Point()
    Private StartPos As Point = New Point()
    Private MousePos As Point = New Point()
    Private MouseIsDown As Boolean = False
    'VARIABLE D'ÉDITIONS
    Private RedimensionneBordure As Boolean = False
    Private RedimensionneCellule As Boolean = False
    Private RedimensionneHauteur As Boolean = False
    Private RedimensionneOppose As Boolean = False
    Private DeplaceCellule As Boolean = False
    Private SelectionCellule As Boolean = False
    Private MouseOverBlock As Integer = -1
    Private SelectedBlock As List(Of Integer) = New List(Of Integer)

    Private colList As New List(Of String)
    Private rowList As New List(Of String)
    Public Semaine As Date = Date.Now
    Private listeEmploye As New List(Of Employe)
    Private listeConge As New List(Of DAL.Conge)
    Private listPlageGrille As New List(Of PlageGrille)
    Private Loading As Boolean = True



    Public Property SelectedPlage() As PlageGrille
        Get
            If listPlageGrille.Count > 0 And SelectedBlock.Count = 1 Then
                Return listPlageGrille.Where(Function(c) c.ID = SelectedBlock(0))(0)
            Else
                Return Nothing
            End If

        End Get
        Set(ByVal value As PlageGrille)
            Dim ind As Integer = listPlageGrille.IndexOf(listPlageGrille.Where(Function(c) c.ID = SelectedBlock(0))(0))
            listPlageGrille(ind) = value
        End Set
    End Property

#End Region

    Private Sub UcGrilleHoraire_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

    End Sub
    Public Sub Reset()
        listPlageGrille.Clear()
        SelectedBlock.Clear()
    End Sub

    Public Sub init()

        InitColonneRangee()
        InitBitmaps()
        AjusterTailles()
        DessinerBordures()
        DessinerEnTeteRangee()
        DessinerEnTeteColonne()
        DessinerGrille(True)
        ReDessiner()
        Loading = False
    End Sub

    Private Sub InitColonneRangee()
        Select Case TypeColonnes
            Case TypeDeTriEnum.Jours
                NbColonne = 7
            Case TypeDeTriEnum.Employes
                NbColonne = listeEmploye.Count
        End Select

        Select Case TypeRangees
            Case TypeDeTriEnum.Employes
                NbRangee = listeEmploye.Count
                HauteurRangeeMin = 50
            Case TypeDeTriEnum.Temps
                NbRangee = 24
                HauteurRangeeMin = 25
        End Select
    End Sub

    'DEBUT GESTION DES INTERACTIONS ********************************************************

    Public Sub SwitchView(ByVal nview As TypeDeTriEnum)
        If nview = TypeDeTriEnum.Employes Then
            TypeColonnes = TypeDeTriEnum.Employes
            TypeRangees = TypeDeTriEnum.Temps

        ElseIf nview = TypeDeTriEnum.Jours Then
            TypeColonnes = TypeDeTriEnum.Jours
            TypeRangees = TypeDeTriEnum.Employes

        End If

        InitColonneRangee()

        InitBitmaps() 'Ajuste la grandeur des bitmaps
        AjusterTailles() 'Ajuste les tailles des colonnes et rangées selon la taille du bitmap de grille et ajuste les barres de défilements
        'Au cas ou les barres de défilements auraient été chachés, réajuster les bitmaps pour qu'il prennent toute la place
        InitBitmaps()
        AjusterTailles()

        HScrollBar1.Value = 0
        VScrollBar1.Value = 0
        ColScroll = 0
        RowScroll = 0

        PlacerPlages() 'place les plages aux bons employes et aux heures/jour selon le mode, et cache ceux qui ne sont pas du jour selectionné (en mode édition jour)
        If TriEmployeParActivite Then
            OrderEmployeByActive() 'place les employes avec des plages horaires en premiers (prend en compte les plage cahcées)
        End If

        PlacerPlages()
        AjusterPlages() 'ajuste l'heure des plages selon leur tailles et position dans la grille
        DessinerBordures()
        DessinerEnTeteColonne()
        DessinerEnTeteRangee()
        DessinerGrille(True)
        ReDessiner(True)
    End Sub

    Public Sub OrderEmployeByActive(Optional replacePlage As Boolean = True)
        listeEmploye = (listeEmploye.OrderByDescending(Function(x) listPlageGrille.Where(Function(c) c.plage.Employe = x.ID And c.Hidden = False).Count > 0)).ThenBy(Function(x) x.Nom).ToList()
        If replacePlage Then
            PlacerPlages() 'replace les plages aux bons employes après être ordornnés
        End If
    End Sub

#Region "MOUSE EVENTS"

    Private Sub UcGrilleHoraire_MouseMove(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

        'CELLULE DU CURSEUR
        Dim ancienneCellule As Point = MouseCell
        MousePos = e.Location
        If NbColonne > 0 AndAlso NbRangee > 0 Then

            CalculerCelluleCurseur(e.Location)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                'DETECTION D'UN DEPLACEMENT OU D'UNE SELECTION DE CELLULES
                'COMMENCER LE DÉPLACEMENT SEULEMENT SI LE CURSEUR A BOUGÉ UN PEU
                Dim dist As Integer = Math.Abs(Math.Sqrt(Math.Pow(StartPos.X - e.X, 2) + Math.Pow(StartPos.Y - e.Y, 2)))
                If MouseIsDown AndAlso SelectedBlock.Count > 0 AndAlso Not DeplaceCellule _
                    AndAlso Cursor = Cursors.SizeAll AndAlso Not Blocked Then
                    DeplaceCellule = True
                End If
                If MouseIsDown And MouseOverBlock = -1 AndAlso Not DeplaceCellule AndAlso Not RedimensionneCellule AndAlso Not Blocked And Not SelectionCellule And dist > 10 Then
                    SelectionCellule = True
                    StartCell = MouseCell

                End If
            End If

        End If

        If Not RedimensionneBordure AndAlso Not DeplaceCellule AndAlso Not RedimensionneCellule AndAlso Not SelectionCellule Then

            'DETECTION DE LA SOURIS AU DESSUS DES BORDURES
            Dim zone As GraphicsPath = New GraphicsPath()
            'HORIZONTAL
            zone.AddLine(0, HSplitterDistance, Me.Width, HSplitterDistance)
            zone.Widen(New Pen(Brushes.White, SplitterWidth + 2))
            If (zone.IsVisible(e.Location)) Then
                MouseOverHSplitter = True
            Else
                MouseOverHSplitter = False
            End If

            'VERTICAL
            zone = New GraphicsPath()
            zone.AddLine(VSplitterDistance, 0, VSplitterDistance, Me.Height)
            zone.Widen(New Pen(Brushes.White, SplitterWidth + 2))
            If (zone.IsVisible(e.Location)) Then
                MouseOverVSplitter = True
            Else
                MouseOverVSplitter = False
            End If
            Dim rec As Rectangle = New Rectangle(VSplitterDistance + SplitterWidth / 2, 0, bmpColonne.Width, bmpColonne.Height)
            'AU DESSUS DES EN-TÊTES
            If NbColonne > 0 And LargeurColonne > 0 Then
                'COLONNES

                If rec.Contains(e.Location) Then
                    Dim temp As Integer
                    temp = Math.Floor((e.X - (VSplitterDistance + SplitterWidth / 2) + ColScroll * LargeurColonne) / LargeurColonne)
                    If Not temp = AuDessusColonne Then
                        If temp >= NbColonne Then
                            temp = -1
                        End If
                        AuDessusColonne = temp

                        DessinerEnTeteColonne()
                        ReDessiner(False)
                    End If

                Else
                    If Not AuDessusColonne = -1 Then
                        AuDessusColonne = -1
                        DessinerEnTeteColonne()
                        ReDessiner(False)
                    End If


                End If
            End If

            'AU DESSUS DE LA GRILLE
            If MouseOverGrid Then
                Dim oldValue As Integer = MouseOverBlock
                MouseOverBlock = -1
                For Each block As PlageGrille In listPlageGrille.OrderByDescending(Function(c) c.Selected).ThenBy(Function(c) c.TabOrder).Where(Function(c) c.Hidden = False)
                    If block.ScreenBound.Contains(New Point(e.X - VSplitterDistance + SplitterWidth / 2, e.Y - HSplitterDistance + SplitterWidth / 2)) Then

                        Dim left, right, top, bottom As Rectangle
                        left = New Rectangle(0, 10, 10, HauteurRangee - 20)
                        right = New Rectangle(LargeurColonne * block.Taille.Width - 9, 10, 10, HauteurRangee * block.Taille.Height - 20)
                        top = New Rectangle(10, 0, LargeurColonne * block.Taille.Width - 20, 10)
                        bottom = New Rectangle(10, HauteurRangee * block.Taille.Height - 9, LargeurColonne * block.Taille.Width - 20, 10)

                        Dim mousePoint As Point = New Point(e.X - block.Position.X * LargeurColonne - (VSplitterDistance + SplitterWidth / 2) + ColScroll * LargeurColonne, _
                                                            e.Y - block.Position.Y * HauteurRangee - (HSplitterDistance + SplitterWidth / 2) + RowScroll * HauteurRangee)
                        If Not Blocked Then

                            If top.Contains(mousePoint) And TypeRangees = TypeDeTriEnum.Temps And SelectedBlock.Count <= 1 Then
                                Cursor = Cursors.SizeNS
                                RedimensionneOppose = False
                            ElseIf left.Contains(mousePoint) And TypeColonnes = TypeDeTriEnum.Jours And SelectedBlock.Count <= 1 Then
                                Cursor = Cursors.SizeWE
                                RedimensionneOppose = False
                            ElseIf right.Contains(mousePoint) And TypeColonnes = TypeDeTriEnum.Jours And SelectedBlock.Count <= 1 Then
                                Cursor = Cursors.SizeWE
                                RedimensionneOppose = True
                            ElseIf bottom.Contains(mousePoint) And TypeRangees = TypeDeTriEnum.Temps And SelectedBlock.Count <= 1 Then
                                Cursor = Cursors.SizeNS
                                RedimensionneOppose = True
                            Else
                                Cursor = Cursors.SizeAll
                            End If
                        End If
                        'REDESSINER LA GRILLE EN METTANT EN ÉVIDANCE LA PAGE HORAIRE SOUS LE CURSEUR (REDESSINER SEULEMENT SI LA PLAGE EST DIFFÉRENTE)
                        MouseOverBlock = block.ID
                        If oldValue = -1 Or Not oldValue = block.ID Then
                            DessinerGrille(Blocked)
                            ReDessiner(False)
                            Dim empIndex = IIf(TypeColonnes = TypeDeTriEnum.Employes, block.Position.X, block.Position.Y)
                            ToolTip1.RemoveAll()
                            Dim heures As String = block.plage.Date.ToShortTimeString() + "-" + block.plage.Date.AddMinutes(block.plage.Duree).ToShortTimeString()
                            Dim desc As String = (block.plage.Note + String.Empty).Replace("\r\n", " ")

                            desc = desc.Substring(0, Math.Min(desc.Length, 50)) + IIf(desc.Length > 50, "...", String.Empty)

                            ToolTip1.SetToolTip(Me, "Type : " + block.plage.Nom + Environment.NewLine + "Employé : " + _
                                                StrConv(listeEmploye(empIndex).Nom + ", " + listeEmploye(empIndex).Prenom, VbStrConv.ProperCase) + Environment.NewLine + _
                                                "Heures : " + heures + Environment.NewLine + _
                                                "Description : " + desc)
                        End If

                        Exit For
                    End If
                Next

                'REDESSINER LA GRILLE QUAND LE CURSEUR NE POINTE AUCUNE PLAGE HORAIRE (SEULEMENT SI IL Y AVAIT UNE PLAGE POINTÉE)
                If Not oldValue = MouseOverBlock And MouseOverBlock = -1 Then
                    DessinerGrille(Blocked)
                    ReDessiner(False)
                    ToolTip1.RemoveAll()
                End If

            End If

        ElseIf RedimensionneBordure Then

            If MouseOverVSplitter Then
                VSplitterDistance = e.X

            End If
            If MouseOverHSplitter Then
                HSplitterDistance = e.Y
            End If
            'APERCU DU REDIMENSIONNEMENT DES BORDURES
            Dim ligneApercu As Pen = New Pen(SystemColors.HotTrack, SplitterWidth)
            Dim offsetx As Integer = IIf(VScrollBar1.Visible, VScrollBar1.Width, 0)
            Dim offsety As Integer = IIf(HScrollBar1.Visible, HScrollBar1.Height, 0)

            Using g As Graphics = Me.CreateGraphics()
                g.DrawImageUnscaled(bmpPricipal, 0, 0)
                If MouseOverVSplitter Then
                    g.DrawLine(ligneApercu, VSplitterDistance, 0, VSplitterDistance, bmpPricipal.Height - offsety)
                End If
                If MouseOverHSplitter Then
                    g.DrawLine(ligneApercu, 0, HSplitterDistance, bmpPricipal.Width - offsetx, HSplitterDistance)
                End If

            End Using
            ligneApercu.Dispose()
        ElseIf DeplaceCellule Then
            If Not MouseCell = ancienneCellule Then
                DessinerGrille()
                ReDessiner(False)
            End If
        ElseIf RedimensionneCellule Then
            If Not MouseCell = ancienneCellule Then
                DessinerGrille()
                ReDessiner(False)
            End If
        ElseIf SelectionCellule Then
            ReDessiner(False)
        End If

        'VERIFIE SI UNE CELLULE EST DÉPLACÉE A L'EXTERIEUR DE LA GRILLE
        Dim cellout As Boolean = False
        If DeplaceCellule Then
            For Each block As PlageGrille In listPlageGrille
                If SelectedBlock.Contains(block.ID) Then
                    If (MouseCell.X - StartCell.X) + block.Position.X < 0 Or (MouseCell.Y - StartCell.Y) + block.Position.Y < 0 _
                        Or (MouseCell.X - StartCell.X) + block.Position.X + block.Taille.Width - 1 >= NbColonne _
                        Or (MouseCell.Y - StartCell.Y) + block.Position.Y + block.Taille.Height - 1 >= NbRangee Then
                        cellout = True
                        Exit For
                    End If
                End If
            Next
        End If
        If RedimensionneCellule And MouseCell = New Point(-1, -1) Then
            cellout = True
        End If
        'test
        If (MouseOverVSplitter And MouseOverHSplitter) Then
            Cursor = Cursors.SizeAll
        ElseIf MouseOverHSplitter Then
            Cursor = Cursors.HSplit
        ElseIf MouseOverVSplitter Then
            Cursor = Cursors.VSplit
        ElseIf MouseOverGrid And Not MouseOverBlock = -1 And Not DeplaceCellule And Not MouseCell = New Point(-1, -1) Then
            If Blocked Then
                Cursor = Cursors.Default
            End If
            'CE IF EMPECHE D'ALLER DANS LE ELSE PARCE QUE LA GESTION DU CURSEUR POUR CETTE CONDITION CE FAIT AILLEUR DANS LE CODE
        ElseIf Not AuDessusColonne = -1 And AuDessusColonne < NbColonne Then
            Cursor = Cursors.Hand
        ElseIf (DeplaceCellule Or RedimensionneCellule) And (cellout Or Not MouseOverGrid) Then
            Cursor = Cursors.No
        ElseIf DeplaceCellule And Not cellout Then
            Cursor = Cursors.SizeAll
        Else
            Cursor = Cursors.Default
        End If
    End Sub

    Private Sub UcGrilleHoraire_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If Not e.Button = Windows.Forms.MouseButtons.Left Then
            If DeplaceCellule Or RedimensionneCellule Or MouseOverHSplitter Or MouseOverVSplitter Then
                Return
            End If

            UcGrilleHoraire_MouseMove(Me, e)
            If Not MouseOverBlock = -1 AndAlso (Cursor = Cursors.Default Or Cursor = Cursors.SizeAll) Then
                Me.ContextMenuStrip = Cms_PlageRightClick
            ElseIf Not Me.ContextMenuStrip Is Nothing Then
                Me.ContextMenuStrip = Nothing
            End If

        Else
            If Not Me.ContextMenuStrip Is Nothing Then
                UcGrilleHoraire_MouseMove(Me, e)
                Me.ContextMenuStrip = Nothing
            End If
            StartPos = e.Location
        End If

        MouseIsDown = True
        'CLICK SUR LES BORDURES REDIMENSIONNABLES
        If MouseOverHSplitter Or MouseOverVSplitter Then
            RedimensionneBordure = True
        End If
        'CLICK SUR UNE COLONNE
        If Not AuDessusColonne = -1 Then
            If TypeColonnes = TypeDeTriEnum.Jours Then
                RaiseEvent ColonneClickEvent(AuDessusColonne, Nothing)
                SwitchView(TypeDeTriEnum.Employes)
                Return
            End If

        End If
        'CLICK SUR UNE PLAGE HORAIRE
        If Not MouseOverBlock = -1 Then
            StartPos = e.Location
            Select Case Cursor

                Case Cursors.SizeAll, Cursors.Default 'DEPLACEMENT
                    StartCell = MouseCell
                    If Not SelectedBlock.Contains(MouseOverBlock) Then
                        If Not Control.ModifierKeys = Keys.Shift Then
                            SelectedBlock.Clear()
                            For Each block In listPlageGrille
                                block.Selected = False
                            Next
                        End If
                        SelectedBlock.Add(MouseOverBlock)
                        listPlageGrille.Where(Function(c) c.ID = MouseOverBlock)(0).Selected = True
                        RaiseEvent PlageSelected(Nothing, Nothing)
                        DessinerGrille(Blocked)
                        ReDessiner(False)
                    Else
                        If SelectedBlock.Count > 1 Then
                            If Control.ModifierKeys = Keys.Shift Then
                                SelectedBlock.Remove(MouseOverBlock)
                                listPlageGrille.Where(Function(c) c.ID = MouseOverBlock)(0).Selected = False
                                RaiseEvent PlageSelected(Nothing, Nothing)
                                DessinerGrille(Blocked)
                                ReDessiner(False)
                            End If
                        End If
                    End If
                Case Cursors.SizeNS, Cursors.SizeWE 'REDIMENSIONNEMENT
                    If SelectedBlock.Count <= 1 Then
                        RedimensionneCellule = True
                        SelectedBlock.Clear()
                        For Each block In listPlageGrille
                            block.Selected = False
                        Next
                        SelectedBlock.Add(MouseOverBlock)
                        listPlageGrille.Where(Function(c) c.ID = MouseOverBlock)(0).Selected = True
                        RaiseEvent PlageSelected(Nothing, Nothing)
                        StartCell = MouseCell
                        DessinerGrille()
                        ReDessiner(False)
                    End If
            End Select
        ElseIf MouseOverGrid Then 'CLICK DANS LE VIDE (SUR LA GRILLE)
            If Not SelectedBlock.Count = 0 AndAlso Not Control.ModifierKeys = Keys.Shift Then
                For Each block In listPlageGrille
                    block.Selected = False
                Next
                SelectedBlock.Clear()
                RaiseEvent PlageSelected(Nothing, Nothing)
                DessinerGrille(Blocked)
                ReDessiner(False)
            End If
        End If
    End Sub

    Private Sub UcGrilleHoraire_MouseUp(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
        If Not e Is Nothing AndAlso Not e.Button = Windows.Forms.MouseButtons.Left Then
            Return
        End If
        MouseIsDown = False
        If RedimensionneBordure Then
            RedimensionneBordure = False
            InitBitmaps()
            AjusterTailles()
            DessinerBordures()
            DessinerEnTeteRangee()
            DessinerEnTeteColonne()
            DessinerGrille()
            ReDessiner()
        End If
        If SelectionCellule Then
            SelectionCellule = False
            If Not Control.ModifierKeys = Keys.Shift Then
                SelectedBlock.Clear()
                For Each block In listPlageGrille
                    block.Selected = False
                Next
            End If
            Dim SelectionRectangle As New Rectangle(Math.Min(StartCell.X, MouseCell.X), Math.Min(StartCell.Y, MouseCell.Y), _
                                                    Math.Abs(MouseCell.X - StartCell.X) + 1, Math.Abs(MouseCell.Y - StartCell.Y) + 1)
            For Each block As PlageGrille In listPlageGrille.Where(Function(c) SelectionRectangle.Contains(c.Position))
                SelectedBlock.Add(block.ID)
                block.Selected = True
            Next
            RaiseEvent PlageSelected(Nothing, Nothing)
            DessinerGrille()
            ReDessiner(False)
        End If

        If DeplaceCellule Then 'Positionnner les plages apres un déplacement
            DeplaceCellule = False
            If MouseCell = StartCell Then
                AjusterPlages()
                DessinerGrille()
                ReDessiner(False)
                Return
            End If
            Dim Changement As Boolean = False
            If Not Cursor = Cursors.No Then
                For Each block As PlageGrille In listPlageGrille.Where(Function(x) SelectedBlock.Contains(x.ID))
                    If block.plage.Accompagnement.HasValue AndAlso block.plage.Accompagnement Then
                        Dim nomBen As String = block.plage.Beneficiaire1.Prenom + " " + block.plage.Beneficiaire1.Nom
                        If MessageBox.Show("Voulez-vous vraiment modifer l'accompagnement de " + nomBen + "?", "Modification d'un accompagnement" _
                                           , MessageBoxButtons.OKCancel, _
                                           MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) = DialogResult.Cancel Then
                            Continue For
                        End If
                    End If
                    If VerifierConges(New Point(block.Position.X + MouseCell.X - StartCell.X, block.Position.Y + MouseCell.Y - StartCell.Y), block) Then
                        MessageBox.Show("Cet employé est indisponible pour cette periode de temps.", "Congés employés", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                        block.SurConge = True
                    Else
                        block.SurConge = False
                    End If
                    Changement = True
                    block.plage.QuartArriere = False
                    block.Position = New Point(block.Position.X + MouseCell.X - StartCell.X, block.Position.Y + MouseCell.Y - StartCell.Y)
                Next

                AjusterPlages()

                DessinerGrille()
                ReDessiner(False)
            Else
                Dim result As DialogResult = MessageBox.Show("Êtes-vous sûr de vouloir supprimer ce(s) plage(s) horaire(s)?", "Déplacement hors grille", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)
                If result = DialogResult.Yes Then
                    SupprimerSelection()

                    Changement = True
                Else
                    listPlageGrille.Where(Function(c) SelectedBlock.Contains(c.ID)).First.TabOrder = 99
                    AjusterPlages()
                    DessinerGrille(True)
                    ReDessiner(False)
                End If
            End If
            If Changement Then
                RaiseEvent modification(True, Nothing)
            End If
            RaiseEvent PlageSelected(Nothing, Nothing)
        End If
        If RedimensionneCellule Then
            RedimensionneCellule = False
            If Not MouseCell = New Point(-1, -1) Then
                Dim changement As Boolean = False
                For Each block As PlageGrille In listPlageGrille
                    If SelectedBlock.Contains(block.ID) Then
                        Dim newPos As Point = block.Position
                        Dim newSize As Size = block.Taille
                        If Cursor = Cursors.SizeNS Then
                            If RedimensionneOppose Then
                                If MouseCell.Y >= block.Position.Y Then
                                    newSize.Height += (MouseCell.Y - StartCell.Y)
                                Else
                                    newPos.Y = (MouseCell.Y - RowScroll)
                                    newSize.Height = (block.Position.Y - MouseCell.Y + 1)
                                End If
                            Else
                                If MouseCell.Y <= (block.Position.Y + block.Taille.Height - 1) Then
                                    newPos.Y -= (StartCell.Y - MouseCell.Y)
                                    newSize.Height += (StartCell.Y - MouseCell.Y)
                                Else
                                    newPos.Y = ((block.Position.Y + block.Taille.Height - 1) - RowScroll)
                                    newSize.Height = (MouseCell.Y - (block.Position.Y + block.Taille.Height - 1) + 1)
                                End If
                            End If
                            Dim tempBlock As New PlageGrille()
                            tempBlock.Taille = newSize
                            If block.plage.Accompagnement.HasValue AndAlso block.plage.Accompagnement Then
                                Dim nomBen As String = block.plage.Beneficiaire1.Prenom + " " + block.plage.Beneficiaire1.Nom
                                If MessageBox.Show("Voulez-vous vraiment modifer l'accompagnement de " + nomBen + "?", "Modification d'un accompagnement" _
                                                   , MessageBoxButtons.OKCancel, _
                                                   MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) = DialogResult.Cancel Then
                                    Continue For
                                End If
                            End If
                            If VerifierConges(newPos, tempBlock) Then
                                MessageBox.Show("Cet employé est indisponible pour cette periode de temps.", "Congés employés", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                                block.SurConge = True
                            Else
                                block.SurConge = False
                            End If
                            changement = True
                            block.Taille = newSize
                            block.Position = newPos
                        End If

                    End If
                Next
                AjusterPlages()
                If changement Then
                    RaiseEvent modification(True, Nothing)
                End If

            End If

            DessinerGrille()
            ReDessiner(False)
        End If

    End Sub

#End Region

    'DESSINS
    Private Sub ReDessiner(Optional ByVal clear As Boolean = True)

        Dim DiffBordure As Integer = SplitterWidth / 2
        Using g As Graphics = Graphics.FromImage(bmpPricipal)
            If clear Or SelectionCellule Then
                g.Clear(Me.BackColor)
            End If
            g.DrawImageUnscaled(bmpRangee, 0, HSplitterDistance + DiffBordure)
            g.DrawImageUnscaled(bmpColonne, VSplitterDistance + DiffBordure, 0)
            g.DrawImageUnscaled(bmpGrille, VSplitterDistance + DiffBordure, HSplitterDistance + DiffBordure)
            g.DrawImageUnscaled(bmpBordure, 0, 0)
            g.DrawRectangle(SystemPens.ControlDark, -1, -1, bmpBordure.Width + 1, bmpBordure.Height + 1)
            If SelectionCellule Then
                Dim dashValues As Single() = {5, 2, 5, 2}
                Dim blackPen As New Pen(Color.Black, 1)
                blackPen.DashPattern = dashValues
                g.DrawRectangle(blackPen, Math.Min(StartPos.X, MousePos.X), Math.Min(StartPos.Y, MousePos.Y), Math.Abs(MousePos.X - StartPos.X), Math.Abs(MousePos.Y - StartPos.Y))
            End If
        End Using
        Using g As Graphics = Me.CreateGraphics()
            g.DrawImageUnscaled(bmpPricipal, 0, 0)
        End Using
    End Sub

#Region "DESSINER"

    Private Sub DessinerEnTeteColonne()

        Using g As Graphics = Graphics.FromImage(bmpColonne)
            'g.Clear(SystemColors.Control)
            Dim ctr As Integer = 0

            Dim rect As New Rectangle(0, 0, bmpColonne.Width, bmpColonne.Height)

            Using br As New LinearGradientBrush(rect, Color.White, Color.FromArgb(230, 230, 240), LinearGradientMode.Vertical)
                g.FillRectangle(br, rect)
            End Using

            Select Case TypeColonnes
                Case TypeDeTriEnum.Jours

                    For i = 0 To 6
                        rect = New Rectangle(LargeurColonne * i - ColScroll * LargeurColonne + 1, 0, LargeurColonne - 1, bmpColonne.Height)
                        If AuDessusColonne = i Then
                            Using br As New LinearGradientBrush(rect, Color.FromArgb(240, 240, 250), Color.FromArgb(200, 200, 210), LinearGradientMode.Vertical)
                                g.FillRectangle(br, rect)
                            End Using
                        End If

                        Dim texte As String = StrConv(Semaine.AddDays(-Semaine.DayOfWeek + i).ToString("dddd", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase) _
                                     + Environment.NewLine + Semaine.AddDays(-Semaine.DayOfWeek + i).Day.ToString() _
                                     + " " + StrConv(Semaine.AddDays(-Semaine.DayOfWeek + i).ToString("MMMM", CultureInfo.GetCultureInfo("fr-CA")), VbStrConv.ProperCase)
                        Dim formatTexte As New StringFormat()
                        formatTexte.Alignment = StringAlignment.Center
                        formatTexte.LineAlignment = StringAlignment.Center

                        g.DrawString(texte, Me.Font, Brushes.Black, rect, formatTexte)
                        g.DrawLine(New Pen(Color.FromArgb(158, 182, 206)), LargeurColonne * (i + 1) - ColScroll * LargeurColonne, 0, LargeurColonne * (i + 1) - ColScroll * LargeurColonne, bmpColonne.Height)

                    Next

                Case TypeDeTriEnum.Employes
                    ctr = 0
                    For Each emp As Employe In listeEmploye
                        If AuDessusColonne = ctr Then
                            rect = New Rectangle(LargeurColonne * ctr - ColScroll * LargeurColonne + 1, 0, LargeurColonne - 1, bmpColonne.Height)

                            Using br As New LinearGradientBrush(rect, Color.FromArgb(240, 240, 250), Color.FromArgb(200, 200, 210), LinearGradientMode.Vertical)
                                g.FillRectangle(br, rect)
                            End Using
                        End If
                        g.DrawString(StrConv(emp.Nom.TrimStart() + ", " + emp.Prenom, VbStrConv.ProperCase), Me.Font, Brushes.Black, 12 + LargeurColonne * ctr - ColScroll * LargeurColonne, bmpColonne.Height / 2 - Me.Font.Height / 2)
                        g.DrawLine(New Pen(Color.FromArgb(158, 182, 206)), LargeurColonne * (ctr + 1) - ColScroll * LargeurColonne, 0, LargeurColonne * (ctr + 1) - ColScroll * LargeurColonne, bmpColonne.Height)
                        ctr += 1
                    Next
            End Select

        End Using
    End Sub

    Private Sub DessinerEnTeteRangee()

        Using g As Graphics = Graphics.FromImage(bmpRangee)
            'g.Clear(SystemColors.Control)

            Dim rect As New Rectangle(0, -RowScroll * HauteurRangee, bmpRangee.Width, Math.Max(HauteurRangee * (NbRangee + 1), bmpRangee.Height))
            Using br As New LinearGradientBrush(rect, Color.White, Color.FromArgb(230, 230, 240), LinearGradientMode.Vertical)
                g.FillRectangle(br, rect)
            End Using
            Dim ctr As Integer = 0
            Select Case TypeRangees
                Case TypeDeTriEnum.Employes

                    For Each emp As Employe In listeEmploye
                        Dim nomEmp As String = StrConv(emp.Nom.TrimStart() + ", " + emp.Prenom, VbStrConv.ProperCase)

                        g.DrawLine(New Pen(Color.FromArgb(158, 182, 206)), 0, HauteurRangee * (ctr + 1) - RowScroll * HauteurRangee, bmpRangee.Width, HauteurRangee * (ctr + 1) - RowScroll * HauteurRangee)
                        Dim photoEmp As Bitmap
                        If Not IsNothing(emp.Photo) Then
                            Dim flux As New IO.MemoryStream(emp.Photo.ToArray, 0, emp.Photo.Length)
                            photoEmp = Image.FromStream(flux, True)
                        Else
                            photoEmp = My.Resources.default_photo
                        End If
                        Dim imgRect As Rectangle
                        Dim w, h As Single
                        If photoEmp.Width > photoEmp.Height Then
                            w = HauteurRangeeMin - 5
                            h = (w * photoEmp.Height) / photoEmp.Width
                            imgRect = New Rectangle(10, HauteurRangee * ctr - RowScroll * HauteurRangee + (HauteurRangee - h) / 2, w, h)
                        Else
                            h = HauteurRangeeMin - 5
                            w = (h * photoEmp.Width) / photoEmp.Height
                            imgRect = New Rectangle(10, HauteurRangee * ctr - RowScroll * HauteurRangee + (HauteurRangee - h) / 2, w, h)
                        End If
                        g.DrawImage(photoEmp, imgRect)
                        g.DrawRectangle(Pens.Black, imgRect)
                        g.DrawString(nomEmp, Me.Font, Brushes.Black, 10 + HauteurRangeeMin, HauteurRangee * ctr + HauteurRangee / 2 - Me.Font.Height / 2 - RowScroll * HauteurRangee)
                        ctr += 1
                    Next
                Case TypeDeTriEnum.Temps

                    Dim time As Date = Date.Now
                    time = time.AddMinutes(-time.Minute)
                    time = time.AddHours(-time.Hour)

                    For i = 0 To 23
                        'g.DrawString("" + time.AddHours(i).ToShortTimeString() + "-" + time.AddHours(i + 1).AddMinutes(-1).ToShortTimeString(), _
                        '             Me.Font, Brushes.Black, 10, HauteurRangee * i + HauteurRangee / 2 - Me.Font.Height / 2 - RowScroll * HauteurRangee)
                        g.DrawString("" + time.AddHours(i).ToShortTimeString(), _
                                     Me.Font, Brushes.Black, 10, HauteurRangee * i + HauteurRangee / 2 - Me.Font.Height / 2 - RowScroll * HauteurRangee)
                        g.DrawLine(New Pen(Color.FromArgb(158, 182, 206)), 0, HauteurRangee * (i + 1) - RowScroll * HauteurRangee, bmpRangee.Width, _
                                   HauteurRangee * (i + 1) - RowScroll * HauteurRangee)
                    Next
            End Select


        End Using
    End Sub

    Private Sub DessinerBordures()
        Using g As Graphics = Graphics.FromImage(bmpBordure)
            Dim distance As Double = SplitterWidth / 2
            g.Clear(Color.Transparent)

            'Coin haut gauche
            'g.FillRectangle(New SolidBrush(Me.BackColor), New Rectangle(0, 0, VSplitterDistance, HSplitterDistance))
            'HORIZONTAL
            g.DrawLine(New Pen(Color.FromArgb(98, 98, 98)), New PointF(0, HSplitterDistance - distance), New PointF(Me.Width, HSplitterDistance - distance))
            g.DrawLine(New Pen(Color.FromArgb(98, 98, 98)), New PointF(0, HSplitterDistance + distance), New PointF(Me.Width, HSplitterDistance + distance))
            'VERTICAL
            g.DrawLine(New Pen(Color.FromArgb(142, 142, 142)), New PointF(VSplitterDistance - distance, 0), New PointF(VSplitterDistance - distance, Me.Height))
            g.DrawLine(New Pen(Color.FromArgb(98, 98, 98)), New PointF(VSplitterDistance + distance, 0), New PointF(VSplitterDistance + distance, Me.Height))
            'ombrage
            Dim leftShadow As New Rectangle(VSplitterDistance - distance - 16, HSplitterDistance + distance, 16, Me.Height - (HSplitterDistance + distance))
            Using br As New LinearGradientBrush(leftShadow, Color.Transparent, Color.FromArgb(40, 40, 40, 40), LinearGradientMode.Horizontal)
                g.FillRectangle(br, leftShadow)
            End Using

            'REPLISSAGE DES BORDURES
            g.DrawLine(New Pen(Color.FromArgb(240, 240, 240), SplitterWidth - 1), 0, HSplitterDistance, Me.Width, HSplitterDistance)
            g.DrawLine(New Pen(Color.FromArgb(240, 240, 240), SplitterWidth - 1), VSplitterDistance, 0, VSplitterDistance, Me.Height)
        End Using
    End Sub

    Private Structure CongeJour
        Public indexCol As Integer
        Public indexRange As Integer
        Public texte As String
    End Structure

    Private Sub DessinerGrille(Optional ByVal clear As Boolean = False)

        Using g As Graphics = Graphics.FromImage(bmpGrille)
            g.SmoothingMode = SmoothingMode.AntiAlias
            'g.CompositingQuality = CompositingQuality.HighQuality
            'g.InterpolationMode = InterpolationMode.HighQualityBilinear
            'GRILLE
            If clear Then
                If Blocked Then
                    g.Clear(Color.FromArgb(142, 142, 142))
                Else
                    g.Clear(Color.FromArgb(240, 240, 240))
                End If

            End If

            If Not Blocked Then
                g.FillRectangle(Brushes.White, 0, 0, LargeurColonne * (NbColonne - ColScroll), HauteurRangee * (NbRangee - RowScroll))
            Else
                g.FillRectangle(New SolidBrush(Color.FromArgb(240, 240, 240)), 0, 0, LargeurColonne * (NbColonne - ColScroll), HauteurRangee * (NbRangee - RowScroll))
            End If

            Dim couleurConge As Color = Color.FromArgb(60, 180, 180, 180)
            Dim formatTexte As New StringFormat()
            formatTexte.Alignment = StringAlignment.Center
            formatTexte.LineAlignment = StringAlignment.Center
            'DESSIN DES CONGES ***************
            If TypeRangees = TypeDeTriEnum.Employes Then
                Dim listeCongeJour As New List(Of CongeJour)

                For Each cong In listeConge
                    Dim indexRangee As Integer = listeEmploye.IndexOf(cong.Employe1)
                    Dim nbJour As Integer
                    Dim indexJour As Integer

                    If cong.DateDebut >= Semaine Then

                        nbJour = CType(IIf(cong.DateFin.Value <= Semaine.AddDays(6), cong.DateFin.Value, Semaine.AddDays(6)), Date).Subtract(cong.DateDebut.Value).Days + 1
                        indexJour = cong.DateDebut.Value.DayOfWeek
                    Else
                        nbJour = CType(IIf(cong.DateFin.Value <= Semaine.AddDays(6), cong.DateFin.Value, Semaine.AddDays(6)), Date).Subtract(Semaine).Days + 1
                        indexJour = 0
                    End If
                    For h = 0 To nbJour - 1
                        Dim coj As New CongeJour
                        coj.texte = cong.Titre
                        coj.indexRange = indexRangee
                        coj.indexCol = indexJour + h
                        listeCongeJour.Add(coj)
                    Next

                Next
                For Each congGroup In (From x In listeCongeJour Group x By key = x.indexCol, key2 = x.indexRange Into Group Select col = key, ran = key2, conG = Group)
                    g.FillRectangle(New SolidBrush(couleurConge), (congGroup.col - ColScroll) * LargeurColonne, _
                                        (congGroup.ran - RowScroll) * HauteurRangee _
                                        , LargeurColonne, HauteurRangee)
                    Dim text As String = String.Empty
                    For Each txt In congGroup.conG
                        text += txt.texte + Environment.NewLine
                    Next
                    g.DrawString(text, Me.Font, Brushes.Black, _
                                     New Rectangle((congGroup.col - ColScroll) * LargeurColonne, _
                                                  (congGroup.ran - RowScroll) * HauteurRangee, LargeurColonne, HauteurRangee), formatTexte)
                Next
            ElseIf TypeRangees = TypeDeTriEnum.Temps Then
                Dim finDeJourne As Date = Semaine.AddDays(1)
                finDeJourne = finDeJourne.AddSeconds(-1)
                Dim fullDay(listeEmploye.Count) As Boolean
                For Each cong In listeConge.OrderByDescending(Function(w) w.ToutJournee)
                    If fullDay(listeEmploye.IndexOf(cong.Employe1)) Then
                        Continue For
                    End If
                    If finDeJourne >= cong.DateDebut.Value And Semaine <= cong.DateFin.Value Then
                        If cong.ToutJournee Then
                            g.FillRectangle(New SolidBrush(couleurConge), (listeEmploye.IndexOf(cong.Employe1) - ColScroll) * LargeurColonne, 0, LargeurColonne, bmpGrille.Height)
                            fullDay(listeEmploye.IndexOf(cong.Employe1)) = True
                        Else
                            g.FillRectangle(New SolidBrush(couleurConge), (listeEmploye.IndexOf(cong.Employe1) - ColScroll) * LargeurColonne, _
                                            (cong.DateDebut.Value.Hour - RowScroll) * HauteurRangee, LargeurColonne, _
                                            (cong.DateFin.Value.Hour - cong.DateDebut.Value.Hour) * HauteurRangee)
                        End If
                    End If
                Next
            End If

            For x = 1 To (NbRangee - RowScroll)
                g.DrawLine(Pens.LightGray, 0, x * HauteurRangee, bmpGrille.Width, x * HauteurRangee)
            Next
            For y = 0 To (NbColonne - ColScroll) - 1
                If TypeColonnes = TypeDeTriEnum.Jours Then
                    If Semaine.AddDays(-Semaine.DayOfWeek + y + ColScroll) = Date.Today Then 'Si la colonne et la journée présente
                        g.FillRectangle(New SolidBrush(Color.FromArgb(60, 220, 220, 255)), LargeurColonne * y, 0, LargeurColonne, bmpGrille.Height)
                    End If
                End If
                g.DrawLine(Pens.LightGray, LargeurColonne * y, 0, LargeurColonne * y, bmpGrille.Height)
            Next
            For x = 1 To (NbRangee - RowScroll)

                g.DrawLine(Pens.LightGray, 0, x * HauteurRangee, bmpGrille.Width, x * HauteurRangee)
            Next
            g.DrawLine(SystemPens.ControlDarkDark, LargeurColonne * (NbColonne - ColScroll), 0, LargeurColonne * (NbColonne - ColScroll), bmpGrille.Height)
            g.DrawLine(SystemPens.ControlDarkDark, 0, (NbRangee - RowScroll) * HauteurRangee, bmpGrille.Width, (NbRangee - RowScroll) * HauteurRangee)
            'PLAGES HORAIRES

            For Each block As PlageGrille In listPlageGrille.OrderBy(Function(c) c.Selected).ThenByDescending(Function(c) c.TabOrder)
                If Not block.Hidden Then
                    DessinerPlageHoraire(g, block, Math.Min(10, HauteurRangee / 4), 5)
                End If

            Next
        End Using
    End Sub

    Private Sub DessinerPlageHoraire(ByVal g As Graphics, ByRef block As PlageGrille, ByVal radius As Integer, ByVal padding As Integer)

        Dim hauteur As Integer = block.Taille.Height * HauteurRangee - padding * 2
        Dim largeur As Integer = block.Taille.Width * LargeurColonne - padding * 2
        Dim x As Integer = (block.Position.X - ColScroll) * LargeurColonne + padding
        Dim y As Integer = (block.Position.Y - RowScroll) * HauteurRangee + padding
        Dim deplace As Boolean = False
        'Dessiner un "preview" de la plage pendant qu'elle est déplacée ou redimensionnée
        If SelectedBlock.Contains(block.ID) And DeplaceCellule Then 'Plage en deplacement
            x += (MouseCell.X - StartCell.X) * LargeurColonne
            y += (MouseCell.Y - StartCell.Y) * HauteurRangee
            deplace = True
        ElseIf SelectedBlock.Contains(block.ID) And RedimensionneCellule Then 'Plage en redimensionnement
            If Cursor = Cursors.SizeNS Then
                If RedimensionneOppose Then
                    If MouseCell.Y >= block.Position.Y Then
                        hauteur += (MouseCell.Y - StartCell.Y) * HauteurRangee
                    Else
                        y = (MouseCell.Y - RowScroll) * HauteurRangee + padding
                        hauteur = (block.Position.Y - MouseCell.Y + 1) * HauteurRangee - padding * 2
                    End If
                Else
                    If MouseCell.Y <= (block.Position.Y + block.Taille.Height - 1) Then
                        y -= (StartCell.Y - MouseCell.Y) * HauteurRangee
                        hauteur += (StartCell.Y - MouseCell.Y) * HauteurRangee
                    Else
                        y = ((block.Position.Y + block.Taille.Height - 1) - RowScroll) * HauteurRangee + padding
                        hauteur = (MouseCell.Y - (block.Position.Y + block.Taille.Height - 1) + 1) * HauteurRangee - padding * 2
                    End If
                End If
            End If
            deplace = True
        Else 'Plages superposées
            Dim totalTabs = TotalCollisionCellule(block, New List(Of PlageGrille)())

            If block.TabOrder >= 0 And totalTabs >= 1 Then

                Dim dist As Integer = (LargeurColonne / 3) / (totalTabs)
                'hauteur -= (totalTabs - 1) * 3
                largeur -= (LargeurColonne / 3)
                x += ((totalTabs) - block.TabOrder) * dist
                'y += block.TabOrder * 3
            End If
        End If

        block.ScreenBound = New Rectangle(x, y, largeur + padding * 2, hauteur + padding * 2)

        'REMPLISSAGE
        Dim interieur As GraphicsPath = New GraphicsPath()
        interieur.FillMode = FillMode.Winding
        interieur.AddEllipse(0 + x, 0 + y, radius * 2, radius * 2)
        interieur.AddEllipse(0 + x, hauteur - radius * 2 + y, radius * 2, radius * 2)
        interieur.AddEllipse(largeur - radius * 2 + x, 0 + y, radius * 2, radius * 2)
        interieur.AddEllipse(largeur - radius * 2 + x, hauteur - radius * 2 + y, radius * 2, radius * 2)
        interieur.AddRectangle(New Rectangle(radius + x, 0 + y, largeur - radius * 2, hauteur))
        interieur.AddRectangle(New Rectangle(0 + x, radius + y, largeur, hauteur - radius * 2))

        Dim gradientFill As New LinearGradientBrush(New Rectangle(x, y, largeur, hauteur), _
                                                                          block.Couleur, _
                                                                          block.Couleur, LinearGradientMode.Vertical)
        Dim color_blend As New ColorBlend
        color_blend.Colors = New Color() {RGBHSL.ModifyBrightness(block.Couleur, 0.9), _
            RGBHSL.ModifyBrightness(block.Couleur, 1.1), _
            RGBHSL.ModifyBrightness(block.Couleur, 0.9)}
        color_blend.Positions = New Single() {0.0, 0.4, 1.0}
        gradientFill.InterpolationColors = color_blend

        Dim bordureInt As GraphicsPath = interieur.Clone()
        bordureInt.FillMode = FillMode.Winding
        Dim bordureExt As GraphicsPath = interieur.Clone()

        bordureInt.Widen(New Pen(Brushes.White, 3))
        bordureExt.Widen(New Pen(Brushes.Black, IIf(SelectedBlock.Contains(block.ID), 6, 5)))
        bordureInt.AddPath(interieur, True)
        bordureExt.AddPath(interieur, True)
        'BORDURE EXTERIEURE
        g.FillPath(Brushes.Black, bordureExt)
        'BORDURE INTERIEURE
        g.FillPath(Brushes.White, bordureInt)
        'REMPLISSAGE
        'g.FillPath(New SolidBrush(block.Couleur), interieur)
        g.FillPath(IIf(block.ID = MouseOverBlock And Not SelectedBlock.Contains(block.ID), gradientFill, New SolidBrush(block.Couleur)), interieur)
        bordureExt.Dispose()
        bordureInt.Dispose()
        interieur.Dispose()
        'gradientFill.Dispose()

        'TEXTE
        'TO DO : TIME FORMAT AS USER PARAMETER
        Dim textFont = Me.Font
        If SelectedBlock.Contains(block.ID) Then
            textFont = New Font(Me.Font.FontFamily, Me.Font.Size, FontStyle.Bold)
        End If
        Dim textColor As New SolidBrush(CouleurContraste(block.Couleur))

        'Nom de la plage horaire
        Dim tempName As String = block.plage.Nom
        Dim strSize As SizeF = g.MeasureString(tempName, textFont)
        While (strSize.Width > largeur - radius)
            tempName = tempName.Substring(0, tempName.Length - 1)
            strSize = g.MeasureString(tempName + "...", textFont)
        End While

        g.DrawString(IIf(tempName = block.plage.Nom, tempName, tempName + "..."), textFont, textColor, New PointF(x + radius / 2, y + radius / 2))

        'Heures de la plage horaire (calculer la nouvelle heure durant un déplacement ou redimensionnement)
        Dim heures As String
        Dim newHauteur As Integer = (hauteur + padding * 2) / HauteurRangee - Math.Floor(block.plage.Date.Minute / 60)
        If SelectedBlock.Contains(block.ID) And (RedimensionneCellule Or DeplaceCellule) And TypeRangees = TypeDeTriEnum.Temps Then
            Dim newHeure As Integer = ((y - padding) / HauteurRangee) + RowScroll

            Dim tempDate = block.plage.Date.AddHours(-block.plage.Date.Hour + newHeure)
            Dim test As Integer = Math.Ceiling(Convert.ToDouble(block.plage.Duree + block.plage.Date.Minute) / 60)
            test = newHauteur - test
            heures = tempDate.ToShortTimeString() + "-" + tempDate.AddMinutes(block.plage.Duree + test * 60).ToShortTimeString()
        Else
            heures = block.plage.Date.ToShortTimeString() + "-" + block.plage.Date.AddMinutes(block.plage.Duree).ToShortTimeString()
        End If

        'Si la plage horaire est d'un cellule d'hauteur, placer l'heure au coté de son nom 
        If (hauteur + padding * 2) / HauteurRangee = 1 And TypeRangees = TypeDeTriEnum.Temps Then
            'g.DrawString(heures, textFont, textColor, x + largeur - radius / 2 - g.MeasureString(heures, textFont).Width, y + radius / 2)
        Else
            g.DrawString(heures, textFont, textColor, x + radius / 2, y + hauteur - radius / 2 - Me.Font.Height)
        End If
        
        If Not deplace AndAlso Not block.plage.QuartArriere Is Nothing AndAlso block.plage.QuartArriere Then
            Dim plageBound As RectangleF = block.ScreenBound
            g.DrawImage(My.Resources.Icon_Quart_32, plageBound.X + plageBound.Width - 32, plageBound.Y - padding * 2)
        End If
        If Not deplace AndAlso block.SurConge Then
            Dim plageBound As RectangleF = block.ScreenBound
            If Not deplace AndAlso Not block.plage.QuartArriere Is Nothing AndAlso block.plage.QuartArriere Then
                g.DrawImage(My.Resources.warning, New Rectangle(plageBound.X + plageBound.Width - 55, plageBound.Y - padding * 2 + 3, 24, 24))
            Else
                g.DrawImage(My.Resources.warning, New Rectangle(plageBound.X + plageBound.Width - 32, plageBound.Y - padding * 2 + 3, 24, 24))
            End If

        End If
    End Sub

#End Region

    Private Sub UcGrilleHoraire_Resize(sender As System.Object, e As System.EventArgs) Handles MyBase.Resize
        If Not Loading Then
            InitBitmaps() 'Ajuste la grandeur des bitmaps
            AjusterTailles() 'Ajuste les tailles des colonnes et rangées selon la taille du bitmap de grille et ajuste les barres de défilements
            'Au cas ou les barres de défilements auraient été chachés, réajuster les bitmaps pour qu'il prennent toute la place
            InitBitmaps()
            AjusterTailles()
            DessinerBordures()
            DessinerEnTeteRangee()
            DessinerEnTeteColonne()
            DessinerGrille(True)
            ReDessiner()
        End If

    End Sub

    Private Sub InitBitmaps()
        'VIDER LES BITMAPS DE LA MEMOIRE
        bmpColonne.Dispose()
        bmpRangee.Dispose()
        bmpGrille.Dispose()
        bmpPricipal.Dispose()
        bmpBordure.Dispose()
        'REDEFINIR LES BITMAPS DE LA BONNE GROSSEUR
        Dim DiffBordure As Integer = SplitterWidth / 2
        Dim offsetx As Integer = IIf(VScrollBar1.Visible, VScrollBar1.Width + 2, 0)
        Dim offsety As Integer = IIf(HScrollBar1.Visible, HScrollBar1.Height + 2, 0)
        bmpColonne = New Bitmap(Me.Width - VSplitterDistance - offsetx - DiffBordure, HSplitterDistance - DiffBordure)
        bmpRangee = New Bitmap(VSplitterDistance - DiffBordure, Me.Height - HSplitterDistance - offsety - DiffBordure)
        bmpGrille = New Bitmap(Math.Max(Me.Width - VSplitterDistance - DiffBordure - offsetx, 1), Math.Max(Me.Height - HSplitterDistance - offsety - DiffBordure, 1))
        bmpPricipal = New Bitmap(Me.Width, Me.Height)
        bmpBordure = New Bitmap(Me.Width - offsetx, Me.Height - offsety)
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
        '"Overrider" la fonction OnPaintBackground et ne rien mettre a l'interieur fait que le "background" ne se dessine plus, ce qui accèlere un peu le dessin sur lui-meme (onPain)
    End Sub

    Private Sub UcGrilleHoraire_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        If DesignMode Then

            InitBitmaps()
            AjusterTailles()
            DessinerBordures()
            DessinerEnTeteRangee()
            DessinerEnTeteColonne()
            DessinerGrille()
            ReDessiner()
        End If
        e.Graphics.DrawImageUnscaled(bmpPricipal, 0, 0)
        'Me.BackgroundImage = bmpPricipal
    End Sub

    Private Sub AjusterTailles()
        'AJUSTER LA TAILLE DES COLONNES ET RANGEES
        If NbColonne > 0 Then
            LargeurColonne = Math.Max(Math.Floor(bmpColonne.Width / NbColonne), LargeurColonneMin)

        End If
        If NbRangee > 0 Then
            HauteurRangee = Math.Max(Math.Floor(bmpRangee.Height / NbRangee), HauteurRangeeMin)
        End If
        'CALCULER LES BARRES DE DEFILEMENTS
        If NbColonne * LargeurColonneMin > bmpColonne.Width Then
            Dim difColonne As Integer = NbColonne - Math.Floor(bmpColonne.Width / LargeurColonne)
            If HScrollBar1.Value > difColonne Then
                HScrollBar1.Value = difColonne
                ColScroll = HScrollBar1.Value
            End If

            HScrollBar1.Maximum = NbColonne - 1
            HScrollBar1.LargeChange = (NbColonne - difColonne)
            HScrollBar1.Visible = True
        Else
            HScrollBar1.Value = 0
            HScrollBar1.Maximum = 0
            HScrollBar1.LargeChange = 0
            HScrollBar1.Visible = False
            ColScroll = 0
        End If

        If NbRangee * HauteurRangeeMin > bmpRangee.Height Then
            Dim difRangee As Integer = NbRangee - Math.Floor(bmpRangee.Height / HauteurRangee)
            If VScrollBar1.Value > difRangee Then
                VScrollBar1.Value = difRangee
                RowScroll = VScrollBar1.Value
            End If
            VScrollBar1.Maximum = NbRangee - 1
            VScrollBar1.LargeChange = (NbRangee - difRangee)
            VScrollBar1.Visible = True
        Else
            VScrollBar1.Value = 0
            VScrollBar1.Maximum = 0
            VScrollBar1.LargeChange = 0
            VScrollBar1.Visible = False
            RowScroll = 0
        End If

        'POSITIONNER LES BARRES DE DEFILEMENTS
        HScrollBar1.Location = New Point(VSplitterDistance, Me.Height - HScrollBar1.Height)
        HScrollBar1.Width = Me.Width - VSplitterDistance - VScrollBar1.Width
        VScrollBar1.Location = New Point(Me.Width - VScrollBar1.Width, HSplitterDistance)
        VScrollBar1.Height = Me.Height - HSplitterDistance - HScrollBar1.Height
    End Sub

    Private Sub HScrollBar1_Scroll(sender As System.Object, e As System.Windows.Forms.ScrollEventArgs) Handles HScrollBar1.Scroll
        ColScroll = HScrollBar1.Value
        DessinerEnTeteColonne()
        DessinerGrille(True)
        ReDessiner(True)
    End Sub

    Private Sub VScrollBar1_Scroll(sender As System.Object, e As System.Windows.Forms.ScrollEventArgs) Handles VScrollBar1.Scroll
        RowScroll = VScrollBar1.Value
        DessinerEnTeteRangee()
        DessinerGrille(True)
        ReDessiner(True)
    End Sub

    Private Sub UcGrilleHoraire_MouseLeave(sender As System.Object, e As System.EventArgs) Handles MyBase.MouseLeave
        Cursor = Cursors.Default
        If Not AuDessusColonne = -1 Then
            AuDessusColonne = -1
            DessinerEnTeteColonne()
            ReDessiner(False)
        End If
    End Sub

    'MANIPULATION DES PLAGES HORAIRES

#Region "GESTION PLAGES"

    Public Sub AjusterPlages() 'ajuste l'heure des plages selon leur tailles et position dans la grille

        'Calculer si il y a des cellules qui contiennent plus d'une plage horaires
        'Calculer l'indentation de ces superpositions
        For Each block As PlageGrille In listPlageGrille
            'If block.TabOrder <> 99 Then
            block.TabOrder = 0
            'End If
        Next
        Dim boundList As List(Of Rectangle) = New List(Of Rectangle)()
        For Each block As PlageGrille In listPlageGrille.Where(Function(c) c.Hidden = False).OrderBy(Function(c) c.Taille.Height).ThenByDescending(Function(c) c.TabOrder)

            Dim bound = New Rectangle(block.Position, block.Taille)
            Dim lastTab As Integer = 0
            For Each rec As Rectangle In boundList.Where(Function(g) g.IntersectsWith(bound))
                Dim tempRec As Rectangle = rec
                For Each blck As PlageGrille In listPlageGrille.Where(Function(c) New Rectangle(c.Position, c.Taille).Equals(tempRec) And c.Hidden = False)
                    If blck.TabOrder > lastTab Then
                        lastTab = blck.TabOrder
                    End If
                Next
            Next
            block.TabOrder = lastTab + 1

            boundList.Add(bound)
        Next
        For Each block As PlageGrille In listPlageGrille
            block.TabOrder -= 1

        Next
        'Ajuster les données des plages selon leur position dans la grille (heure, employé associé)
        If TypeRangees = TypeDeTriEnum.Employes Then
            For Each block As PlageGrille In listPlageGrille
                If block.plage.ID = 0 Then
                    block.plage.Employe = listeEmploye(block.Position.Y).ID
                Else
                    block.plage.Employe1 = listeEmploye(block.Position.Y)
                End If

            Next
        End If
        If TypeColonnes = TypeDeTriEnum.Employes Then
            For Each block As PlageGrille In listPlageGrille
                If block.plage.ID = 0 Then
                    block.plage.Employe = listeEmploye(block.Position.X).ID
                Else
                    block.plage.Employe1 = listeEmploye(block.Position.X)
                End If
            Next
        End If
        If TypeRangees = TypeDeTriEnum.Temps Then
            For Each block As PlageGrille In listPlageGrille
                block.plage.Date = block.plage.Date.AddHours(block.Position.Y - block.plage.Date.Hour)

                Dim test As Integer = Math.Ceiling(Convert.ToDouble(block.plage.Duree + block.plage.Date.Minute) / 60)
                test = block.Taille.Height - test
                block.plage.Duree += test * 60
            Next
        End If
        If TypeColonnes = TypeDeTriEnum.Jours Then
            For Each block As PlageGrille In listPlageGrille
                block.plage.Date = New Date(Semaine.AddDays(-Semaine.DayOfWeek + block.Position.X).Year, _
                                          Semaine.AddDays(-Semaine.DayOfWeek + block.Position.X).Month, _
                                          Semaine.AddDays(-Semaine.DayOfWeek + block.Position.X).Day, _
                                          block.plage.Date.Hour, block.plage.Date.Minute, 0)
            Next
        End If

    End Sub

    Public Sub PlacerPlages() 'place les plages aux bons jours/heures et aux bons employés

        For Each block As PlageGrille In listPlageGrille
            Dim x, y As Integer
            If TypeColonnes = TypeDeTriEnum.Jours And TypeRangees = TypeDeTriEnum.Employes Then
                block.Hidden = False
                If block.plage.ID = 0 Then
                    y = listeEmploye.IndexOf(listeEmploye.Where(Function(c) c.ID = block.plage.Employe).First())
                Else
                    y = listeEmploye.IndexOf(block.plage.Employe1)
                End If

                If y = -1 Then
                    y = 0
                End If
                x = block.plage.Date.DayOfWeek
                block.Taille = New Size(1, 1)
            End If
            If TypeColonnes = TypeDeTriEnum.Employes And TypeRangees = TypeDeTriEnum.Temps Then
                If block.plage.Date.DayOfYear <> Semaine.DayOfYear Then
                    block.Hidden = True
                Else
                    block.Hidden = False
                End If
                x = listeEmploye.IndexOf(listeEmploye.Where(Function(c) c.ID = block.plage.Employe).First())
                If x = -1 Then
                    x = 0
                End If
                y = Math.Floor(New TimeSpan(block.plage.Date.Hour, block.plage.Date.Minute, 0).TotalMinutes / 60)

                block.Taille = New Size(1, Math.Ceiling(Convert.ToDouble(block.plage.Duree + block.plage.Date.Minute) / 60))
            End If
            block.Couleur = System.Drawing.ColorTranslator.FromHtml(block.plage.Couleur)
            block.Position = New Point(x, y)
        Next
        VerifierConges(Nothing, Nothing)
    End Sub

    Public Sub SetPlageList(ByVal listPlage As List(Of PlageHoraire))
        listPlageGrille.Clear()
        If listeEmploye.Count = 0 Then
            Return
        End If
        For Each plage As PlageHoraire In listPlage
            Dim block As PlageGrille = New PlageGrille(plage)
            block.Taille = New Size(1, 1)
            block.Couleur = System.Drawing.ColorTranslator.FromHtml(plage.Couleur)
            listPlageGrille.Add(block)
        Next
        listeConge.Clear()
        For Each emp In listeEmploye
            For Each cong In (From x In emp.Conges Where x.DateFin >= Semaine And x.DateDebut <= Semaine.AddDays(6) Select x).ToList
                listeConge.Add(cong)
            Next
        Next
        If TriEmployeParActivite Then
            OrderEmployeByActive() 'place les employes avec des plages horaires en premiers (prend en compte les plage cahcées)
        End If
    End Sub

    Public Sub SetEmployeList(ByVal listE As List(Of DAL.Employe))
        listeEmploye = listE
        If TriEmployeParActivite Then
            OrderEmployeByActive(False) 'place les employes avec des plages horaires en premiers (prend en compte les plage cahcées)
        End If
    End Sub

    Private Function TotalCollisionCellule(ByVal block As PlageGrille, Optional ByVal alreadyProcessed As List(Of PlageGrille) = Nothing, Optional ByRef count As Integer = 0) As Integer

        For Each blck As PlageGrille In listPlageGrille.Where(Function(c) _
                                                                  New Rectangle(c.Position, c.Taille).IntersectsWith(New Rectangle(block.Position, block.Taille)) _
                                                                  And Not alreadyProcessed.Contains(c) And Not c.Equals(block) And c.Hidden = False
                                                                  )
            If blck.TabOrder > count Then
                count = blck.TabOrder
            End If
            alreadyProcessed.Add(blck)
            TotalCollisionCellule(blck, alreadyProcessed, count)
        Next

        Return count
    End Function

    Public Function GetPlages() As List(Of PlageHoraire)
        Dim tempList As New List(Of PlageHoraire)
        For Each block As PlageGrille In listPlageGrille
            tempList.Add(block.plage)
        Next
        Return tempList
    End Function

    Public Sub AddPlageStocke(ByVal plage As PlageHoraireStocke)

        Dim tempPlage As PlageHoraire = New PlageHoraire()

        tempPlage.Nom = plage.Nom

        tempPlage.Date = New Date(Semaine.Year, Semaine.Month, Semaine.Day, 0, 0, 0).Add(plage.HeureDebut)

        tempPlage.Duree = IIf(Not plage.Duree Is Nothing, plage.Duree, 120)
        tempPlage.Couleur = plage.Couleur
        tempPlage.Employe = 1
        tempPlage.Note = plage.Description
        tempPlage.QuartArriere = False
        Dim block As PlageGrille = New PlageGrille(tempPlage)
        If TypeColonnes = TypeDeTriEnum.Jours Then
            block.Taille = New Size(1, 1)
        ElseIf TypeRangees = TypeDeTriEnum.Temps Then
            block.Taille = New Size(1, Math.Ceiling(Convert.ToDouble(block.plage.Duree + block.plage.Date.Minute) / 60))
        End If
        block.Hidden = False
        block.Position = New Point(1, 1)

        block.Couleur = System.Drawing.ColorTranslator.FromHtml(tempPlage.Couleur)
        listPlageGrille.Add(block)

    End Sub

    Public Sub PlacerRecurrence(ByVal rec As Recurrence)
        Dim tempPlage As PlageHoraire = New PlageHoraire()
        tempPlage.Nom = rec.Nom

        tempPlage.Date = New Date(Semaine.Year, Semaine.Month, Semaine.Day - Semaine.DayOfWeek + rec.Jour, 0, 0, 0).Add(rec.Heure)

        tempPlage.Duree = IIf(Not rec.Durée Is Nothing, rec.Durée, 120)
        tempPlage.Couleur = rec.Couleur
        tempPlage.Employe = rec.Employe
        tempPlage.Note = rec.Note
        If rec.Accompagnement.HasValue AndAlso rec.Accompagnement Then
            tempPlage.Accompagnement = True
            tempPlage.Beneficiaire = rec.Beneficiaire
        Else
            tempPlage.Accompagnement = False
        End If
        tempPlage.QuartArriere = False

        Dim block As PlageGrille = New PlageGrille(tempPlage)
        If TypeColonnes = TypeDeTriEnum.Jours Then
            block.Taille = New Size(1, 1)
        ElseIf TypeRangees = TypeDeTriEnum.Temps Then
            block.Taille = New Size(1, Math.Ceiling(Convert.ToDouble(block.plage.Duree + block.plage.Date.Minute) / 60))
        End If
        block.Hidden = False
        block.Position = New Point(1, 1)

        block.Couleur = System.Drawing.ColorTranslator.FromHtml(tempPlage.Couleur)
        listPlageGrille.Add(block)

    End Sub

    Public Function VerifierConges(Optional ByVal pos As Point = Nothing, Optional ByVal block As PlageGrille = Nothing) As Boolean
        If Not block Is Nothing Then
            If TypeColonnes = TypeDeTriEnum.Jours Then
                Dim plageDebut, plageFin As Date
                plageDebut = Semaine.AddDays(pos.X)
                plageDebut = plageDebut.Add(block.plage.Date.TimeOfDay)
                plageFin = plageDebut.AddMinutes(block.plage.Duree)
                If (From x In listeConge Where plageFin >= x.DateDebut.Value And plageDebut < x.DateFin.Value _
                    And x.Employe1.ID = listeEmploye(pos.Y).ID Select x).Count > 0 Then
                    Return True
                Else
                    Return False
                End If
            Else
                Console.WriteLine(Semaine.AddHours(pos.Y + block.Taille.Height).ToString + "  " + Semaine.AddHours(pos.Y).ToString)
                If (From x In listeConge Where Semaine.AddHours(pos.Y + block.Taille.Height) >= x.DateDebut.Value And Semaine.AddHours(pos.Y) < x.DateFin.Value _
                    And x.Employe1.ID = listeEmploye(pos.X).ID Select x).Count > 0 Then
                    Return True
                Else
                    Return False
                End If
            End If
        Else
            For Each blck In listPlageGrille.Where(Function(x) x.Hidden = False)
                If (From x In listeConge Where blck.plage.Date.AddMinutes(blck.plage.Duree) >= x.DateDebut.Value And blck.plage.Date < x.DateFin.Value _
                    And x.Employe1.ID = blck.plage.Employe Select x).Count > 0 Then
                    blck.SurConge = True
                Else
                    blck.SurConge = False
                End If
            Next
        End If
        Return False
    End Function
#End Region


    Private Sub UcGrilleHoraire_DragOver(sender As System.Object, e As System.Windows.Forms.DragEventArgs) Handles MyBase.DragOver

        CalculerCelluleCurseur(Me.PointToClient(Cursor.Position))
        If (MouseOverGrid AndAlso e.Data.GetDataPresent(DataFormats.Text)) Then

            If Not DeplaceCellule And listPlageGrille.Count > 0 Then
                SelectedBlock.Clear()
                SelectedBlock.Add(listPlageGrille(listPlageGrille.Count - 1).ID)
                StartCell = MouseCell
                listPlageGrille(listPlageGrille.Count - 1).Position = MouseCell
                DeplaceCellule = True
            End If
            e.Effect = DragDropEffects.All

            DessinerGrille()
            ReDessiner(False)

        Else
            If DeplaceCellule Then
                DessinerGrille()
                ReDessiner(False)
            End If

            ' Display the no-drop cursor.
            e.Effect = DragDropEffects.None
        End If
    End Sub

    Private Sub CalculerCelluleCurseur(ByVal point As Point)
        If New Rectangle(VSplitterDistance + SplitterWidth / 2, HSplitterDistance + SplitterWidth / 2, bmpGrille.Width, bmpGrille.Height).Contains(point) Then
            Dim col As Integer, ran As Integer
            col = Math.Floor((point.X - (VSplitterDistance + SplitterWidth / 2) + ColScroll * LargeurColonne) / LargeurColonne)
            ran = Math.Floor((point.Y - (HSplitterDistance + SplitterWidth / 2) + RowScroll * HauteurRangee) / HauteurRangee)
            If col >= NbColonne Or ran >= NbRangee Then
                If Not SelectionCellule Then
                    MouseCell = New Point(-1, -1)
                End If

                MouseOverGrid = False
            Else
                MouseCell = New Point(col, ran)
                MouseOverGrid = True
            End If
        Else
            MouseOverGrid = False
            If Not SelectionCellule Then
                MouseCell = New Point(-1, -1)
            End If

            If Not MouseOverBlock = -1 Then 'Le curseur était au dessus d'une cellule mais ne l'ai plus
                MouseOverBlock = -1
                DessinerGrille()
                ReDessiner(False)
            End If
        End If
    End Sub

    Private Sub UcGrilleHoraire_DragDrop(sender As System.Object, e As System.Windows.Forms.DragEventArgs) Handles MyBase.DragDrop
        UcGrilleHoraire_MouseUp(Me, Nothing)
        RaiseEvent modification(True, Nothing)
    End Sub

    Private Sub UcGrilleHoraire_DragLeave(sender As System.Object, e As System.EventArgs) Handles MyBase.DragLeave
        listPlageGrille.RemoveAt(listPlageGrille.Count - 1)
        SelectedBlock.Clear()
        DeplaceCellule = False
        DessinerGrille()
        ReDessiner(False)
    End Sub

    Private Sub DétailsToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles DétailsToolStripMenuItem.Click
        RaiseEvent ViewDetail(SelectedPlage, Nothing)
    End Sub

    Private Sub SupprimerSelection()

        For Each pl In (From x In listPlageGrille Where SelectedBlock.Contains(x.ID) Where x.plage.ID <> 0 Select x.plage).ToList

            bd.Taches.DeleteAllOnSubmit(From x In pl.Taches Where x.ID <> 0 Select x)
            pl.Taches = Nothing
        Next

        bd.PlageHoraires.DeleteAllOnSubmit(From x In listPlageGrille Where SelectedBlock.Contains(x.ID) Where x.plage.ID <> 0 Select x.plage)

        listPlageGrille.RemoveAll(Function(x) SelectedBlock.Contains(x.ID))

        SelectedBlock.Clear()
        RaiseEvent PlageSelected(Nothing, Nothing)
        RaiseEvent modification(True, Nothing)

        DessinerGrille()
        ReDessiner(False)
    End Sub

    Private Sub SupprimerToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SupprimerToolStripMenuItem.Click
        SupprimerSelection()

    End Sub

    Private Sub Cms_PlageRightClick_Opening(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles Cms_PlageRightClick.Opening
        If SelectedBlock.Count > 1 Then
            DétailsToolStripMenuItem.Enabled = False
        Else
            DétailsToolStripMenuItem.Enabled = True
        End If
        SupprimerToolStripMenuItem.Enabled = Not Blocked
    End Sub
End Class
